import { type Post, type Tag } from '@prisma/client';
import _ from 'lodash';
import { db } from '~/server/db';
import { postService } from '~/server/service/post-service';
import { postTagService } from '~/server/service/user-tag-service';
import { clearCache, withCache } from '../cache';

const POST_CACHE_PREFIX = 'charlotte:cache:app:post';

type PostAndTags = { post: Post; tags: Tag[] } | null;

async function findPostForReading(postId: bigint): Promise<PostAndTags> {
  const post = await postService.findById(db, postId);
  if (!post) {
    return null; // not found
  }

  if (post.deleteTime) {
    return null; // deleted
  }

  const tagIds = (post.tagIds as string[]).map((it) => BigInt(it));
  const tags: Tag[] = await postTagService.findByIds(db, tagIds);
  return { post, tags };
}

async function findForUpdating(postId: bigint, authorId: bigint): Promise<PostAndTags> {
  const post = await postService.findByIdAndUserId(db, postId, authorId);
  if (!post) {
    return null; // not found
  }

  const tagIds = (post.tagIds as string[]).map((it) => BigInt(it));
  const tags = await postTagService.findByIds(db, tagIds);
  return { post, tags };
}

type UpdatePost = {
  id: bigint;
  title: string;
  content: string;
  tagIds: string[];
  userId: bigint;
};

async function updatePost(opts: UpdatePost) {
  await postService.update(db, {
    id: opts.id,
    title: opts.title,
    content: opts.content,
    tagIds: opts.tagIds,
    userId: opts.userId,
  });
  await clearCache(POST_CACHE_PREFIX, opts.id.toString());
}

export const postApp = {
  findPostForReading: (postId: bigint) =>
    withCache({
      prefix: POST_CACHE_PREFIX,
      key: postId.toString(),
      load: async () => await findPostForReading(postId),
      ex: 60 * 60 * 27,
    })(),
  findForUpdating,
  updatePost,
};
